使用shiro完成权限判断 您所在的位置:网站首页 shiro 获取当前用户拥有的权限 使用shiro完成权限判断

使用shiro完成权限判断

2023-08-16 02:21| 来源: 网络整理| 查看: 265

一、权限判断 获取到所有权限进行判断,应该从数据库中获取 public class FilterChainDefinitionMapFactory { @Autowired private IPermissionService iPermissionService; public LinkedHashMap builderFilterChainDefinitionMap(){ LinkedHashMap linkedHashMap = new LinkedHashMap(); //anon 不需要登陆就可以访问 authc需要登陆才可以访问 per[xx:xx]需要授权才可以 linkedHashMap.put("/s/login.jsp", "anon"); linkedHashMap.put("/login", "anon"); linkedHashMap.put("*.js","anon"); linkedHashMap.put("*.css","anon"); linkedHashMap.put("/css/**","anon"); linkedHashMap.put("/js/**","anon"); linkedHashMap.put("/easyui/**","anon"); linkedHashMap.put("/images/**","anon"); //linkedHashMap.put("/dept/index", "perms[dept:index]"); //linkedHashMap.put("/employee/index", "perms[employee:index]"); List list = iPermissionService.findAll(); System.out.println(list); list.forEach(e-> linkedHashMap.put(e.getUrl(), "permsFilter["+e.getSn()+"]") ); linkedHashMap.put("/**", "authc"); return linkedHashMap; } } 怎么拿到登录用户 @Override protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException { //先拿用户传过来的令牌 UsernamePasswordToken token = (UsernamePasswordToken)authenticationToken; //拿到令牌的用户 String username = token.getUsername(); Employee loginUser = iEmployeeService.findByUsername(username); if (loginUser==null){ return null; } //加盐验证 //要想使用,还需要在xml配置加密次数,和加密算法。。才可以正确解密验证 ByteSource salt = ByteSource.Util.bytes("itsource"); System.out.println(loginUser.getPassword()+"=====================测试======================="); SimpleAuthenticationInfo simpleAuthenticationInfo = new SimpleAuthenticationInfo(loginUser,loginUser.getPassword(),salt,getName()); return simpleAuthenticationInfo; }

修改页面展示: 主页面的用户现在变成了这个样子 在这里插入图片描述

修改代码: 欢迎[ ]登录,退出 二、完成了登陆验证,将用户存入session 为了以后方便,创建一个工具类专门存取用户 /** * 该工具可以将当前主体对象存入到session中去 * */ public class UserContext { public static final String LOGINUSER = "loginUser"; public static void setUser(){ /*先得到全局的授权主体*/ Subject subject = SecurityUtils.getSubject(); //得到session Session session = subject.getSession(); /*将该主题对象存入到session*/ Employee loginUser = (Employee)subject.getPrincipal(); session.setAttribute(LOGINUSER, loginUser); } public static Employee getUser(){ /*先拿到主体employ对象*/ Subject subject = SecurityUtils.getSubject(); //拿到session Session session = subject.getSession(); //拿到session中的对象 Employee employee = (Employee)session.getAttribute(LOGINUSER); return employee; } } LoginController:登录成功后把用户放到Session中 @RequestMapping(value="/login",method = RequestMethod.POST) @ResponseBody public SuccessBoolean login(String username,String password){ System.out.println("===========================jll"); Subject subject = SecurityUtils.getSubject(); UsernamePasswordToken token = new UsernamePasswordToken(username, password); if (!subject.isAuthenticated()){ try { subject.login(token); } catch (UnknownAccountException e) { System.out.println("用户名不存在"); return new SuccessBoolean(false,"用户名不存在"); } catch (IncorrectCredentialsException e) { System.out.println("密码错误"); e.printStackTrace(); return new SuccessBoolean(false,"用户名不存在或者密码错误"); } catch (AuthenticationException e) { System.out.println("未知错误"); e.printStackTrace(); return new SuccessBoolean(false,"未知错误"); } } //使用工具存入session中 UserContext.setUser(); //如果登陆验证失败,要访问首页还是会被拦截下来 return new SuccessBoolean(); } 三、根据用户id拿到权限 完成权限的判断 其它完成权限,就是通过当前登录用户拿到所有权限,然后去判断当前用户是否有咱们当前访问的这个路径的权限!

PermissionRepository

@Query("select p.sn from Employee o join o.roles r join r.permissions p where o.id=?1") Set findPermissionSnByUserID(Long id);

IPermissionService

在这里插入代码片

PermissionServiceImpl

@Override public Set findPermissionSnByUserID(Long id) { Set permissions = permissionRepository.findPermissionSnByUserID(id); return permissions; } 自定义Realm:进入权限判断 @Override protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) { //拿到主角。。登陆方法验证传过来的是什么 这里就是什么。。 Employee loginUser = (Employee)principalCollection.getPrimaryPrincipal(); //核心管理器会调用doGetAuthorizationInfo方法得到这个用户的权限和角色 //设置到权限的对象并且返回 Set permissions = iPermissionService.findPermissionSnByUserID(loginUser.getId()); //将权限改成从数据库中查找出来。。进行判断 SimpleAuthorizationInfo authorizationInfo = new SimpleAuthorizationInfo(); authorizationInfo.setStringPermissions(permissions); //返回权限对象 return authorizationInfo; } 四、测试,并且完成自定义过滤器

以上功能完成后,我们就可以测试咱们的用户是否有相应的权限! 测试 当没有删除权限时,删除报错 在这里插入图片描述 需要的结果是,点击删除,删除失败,后台返回没有权限的结果 在这里插入图片描述 原因,在请求是Ajax请求时,这个删除是Ajax,后台响应返回的就是一个没有权限时的我们自己设置的页面,他把整个全返回了,我们仅仅需要一个失败原因 在这里插入图片描述 想要的是json的结果字符串。。

咱们所有的请求可以分为两大类,一个是跳转页面,xxx/index 还有一类是Ajax请求期望返回的是{“success”:false,”message”:”没有权限”}

区分处理是否是Ajax请求,普通跳转页面的请求 ,就跳转没有权限的页面,如果是ajax请求返回{“success”:false,”message”:”没有权限”}

怎么判断Ajax 判断请求头里面是否有X-Requested-With 跳转页面请求头 在这里插入图片描述

Ajax请求多个一个请求头X-Requested-With XMLHttpRequest 在这里插入图片描述* 所以自定义拦截器 因为shiro自带的拦截器不区分请求,所以不能达到需要的请求需要结果

/** * 将自定义过滤器交给shiro,改变shiro的默认过滤器配置 * */ //继承PermissionsAuthorizationFilter ,覆写方法 public class AISellPermissionsAuthorizationFilter extends PermissionsAuthorizationFilter { @Override protected boolean onAccessDenied(ServletRequest request, ServletResponse response) throws IOException { Subject subject = this.getSubject(request, response); HttpServletRequest httpServletRequest = (HttpServletRequest)request; HttpServletResponse httpServletResponse = (HttpServletResponse) response; if (subject.getPrincipal() == null) { this.saveRequestAndRedirectToLogin(request, response); } else { //根据请求确定是什么请求 String xRequestedWith = httpServletRequest.getHeader("X-Requested-With"); if (xRequestedWith != null &&"XMLHttpRequest".equals(xRequestedWith)) { //3.在这里就代表是ajax请求 //表示ajax请求 {"success":false,"message":"没有权限"} //返回结果 httpServletResponse.setContentType("text/json; charset=UTF-8"); httpServletResponse.getWriter().print("{\"success\":false,\"msg\":\"没有权限\"}"); }else { String unauthorizedUrl = this.getUnauthorizedUrl(); if (StringUtils.hasText(unauthorizedUrl)) { WebUtils.issueRedirect(request, response, unauthorizedUrl); } else { WebUtils.toHttp(response).sendError(401); } } } return false; } } 把过滤器交给shiro,配置applicationContext-shiro.xml 修改自动权限设置的工具类FilterChainDefinitionMapFactory 修改权限 linkedHashMap.put(e.getUrl(), “permsFilter[”+e.getSn()+"]") public class FilterChainDefinitionMapFactory { @Autowired private IPermissionService iPermissionService; public LinkedHashMap builderFilterChainDefinitionMap(){ LinkedHashMap linkedHashMap = new LinkedHashMap(); /* /s/login.jsp = anon /login = anon /dept/index = perms[dept:index] /employee/index = perms[employee:index] /** = authc * */ //anon 不需要登陆就可以访问 authc需要登陆才可以访问 per[xx:xx]需要授权才可以 linkedHashMap.put("/s/login.jsp", "anon"); linkedHashMap.put("/login", "anon"); linkedHashMap.put("*.js","anon"); linkedHashMap.put("*.css","anon"); linkedHashMap.put("/css/**","anon"); linkedHashMap.put("/js/**","anon"); linkedHashMap.put("/easyui/**","anon"); linkedHashMap.put("/images/**","anon"); //linkedHashMap.put("/dept/index", "perms[dept:index]"); //linkedHashMap.put("/employee/index", "perms[employee:index]"); List list = iPermissionService.findAll(); System.out.println(list); list.forEach(e-> linkedHashMap.put(e.getUrl(), "permsFilter["+e.getSn()+"]") ); linkedHashMap.put("/**", "authc"); return linkedHashMap; } } 五、菜单读取

没有url的就是父菜单,根目录。。 用户->角色->权限->菜单 用户有哪些权限,就应该有对应的菜单 (这里咱们可以分析数据库理解设计) 用户拥有对应的权限就拥有对应的菜单(二级菜单),如果此菜单有父菜单(一级菜单)也同时拥有

Domain设计 @Entity @Table(name="menu") public class Menu extends BaseDomain { private String name;//菜单名称 private String url; //路径 private String icon; //图标 /** * JsonIgnore:生成JSON的时候忽略这个属性 */ @ManyToOne(fetch = FetchType.LAZY) @JoinColumn(name="parent_id") @JsonIgnore //这里生成json的时候要忽略,否则会造成功能相互调用 private Menu parent; /** * 还要配置一个一对多 * 这个字段不要交给JPA管理【到时候自己写代码管理】 * 数据库的menu表中就应该有一个children,而且还是List类型 * Transient:临时属性(JPA不管这个属性,和数据库没有关系) */ @Transient private List children = new ArrayList(); … public String getText(){ //EasyUI的树需要一个text属性 return name; } }

因为前台的名字是叫Text public String getText(){ //EasyUI的树需要一个text属性 return name;}

多个权限可以对应一个菜单 比如系统管理菜单下面可以有员工的管理等等 数据管理菜单也可以管理员工。。等等 所以权限和菜单是多对一关系

Permission类 @ManyToOne(fetch = FetchType.LAZY) @JoinColumn(name="menu_id") private Menu menu;

MenuRepository 员工和角色多对多,一个员工可能有多个角色 一个角色可能多个权限,每一个权限对应一个menu 每一个权限permission对象中就有一个menu对象 每一个menu对象都有一个parent字段, 一个人通过permission去查menu,查到的menu只有子菜单, Permission 中的 menu 全是子菜单 只要有子菜单就一定有父菜单

比如一个user,有员工管理权力8,查询得到的是id为8的menu对象,这个menu一定有一个父菜单字段parent,6号

在这里插入图片描述在这里插入图片描述

MenuRepository @Query("select p.sn from Employee o join o.roles r join r.permissions p where o.id=?1") Set findPermissionSnByUserID(Long id); IMenuService List findByUserId(); MenuServiceImpl @Override public List findByUserId() { Employee loginUser = UserContext.getUser(); //拿到所有的菜单menu对象 List menuList = menuRepository.findByUserId(loginUser.getId()); //准备一个父菜单容器 仅仅是存入子菜单返回给前台 List parentList = new ArrayList(); //遍历查询的所以菜单 for (int i = 0;i


【本文地址】

公司简介

联系我们

今日新闻

    推荐新闻

    专题文章
      CopyRight 2018-2019 实验室设备网 版权所有